package
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.filters.DropShadowFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Transform;
	
	public class LetterGrid extends Sprite
	{
		private const ORIENTATION_HORIZONTAL:String = "horizontal";
		private const ORIENTATION_VERTICAL:String = "vertical";
		
		private const _wordWidth:int = 5;//width in letters
		private const _gridWidth:int = 13; //width in letters
		private const _gridHeight:int = 8; //height in letters
		private var _words:Array;
		private var _lettersGrid:Array;
		private var _isMouseDown:Boolean=false;
		private var _wordDragBuffer:Vector.<LetterBox>;
		private var _firstLetterBox:Sprite;
		private var _hightLight:Sprite;
		
		public function LetterGrid()
		{
			filters = [new DropShadowFilter()];
		}
		
		public function newGame(words:Array):void
		{
			cleanUp();
			
			_words = words;
			
			var counter:int = 0;
			var word:String = words[counter];
			var startingCol:int;
			var startingRow:int;
			
			//create 3 horizontal words
			while (counter < 3)
			{
				word = String(words[counter]).toUpperCase();
				
				startingCol = int(Math.random() * (_gridWidth - _wordWidth));
				startingRow = int(Math.random() * (_gridHeight));
				
				if(isValid(word, startingRow, startingCol, ORIENTATION_HORIZONTAL)){
					counter++;
				}
			}
			
			//create 3 verticle words
			while (counter < 6)
			{
				word = String(words[counter]).toUpperCase();
				
				startingCol= int(Math.random() * (_gridWidth));
				startingRow = int(Math.random() * (_gridHeight - _wordWidth));
				
				if (isValid(word, startingRow, startingCol, ORIENTATION_VERTICAL)) {
					counter++;
				}
			}
			
			//after adding words, replace remaining *'s with random letters
			fillGrid();
			
			drawGrid();
		}
		
		private function drawGrid():void
		{
			for (var r:int = 0; r < _gridHeight; r++) {
				for (var c:int = 0; c < _gridWidth; c++) {
					var letter:LetterBox = new LetterBox(String(_lettersGrid[r][c]));
					letter.x = c * LetterBox.SIZE;
					letter.y = r * LetterBox.SIZE;
					letter.addEventListener(MouseEvent.MOUSE_DOWN, onLetterMouseDown);
					letter.addEventListener(MouseEvent.MOUSE_OVER, onLetterMouseOver);
					stage.addEventListener(MouseEvent.MOUSE_UP, onLetterMouseUp);
					addChild(letter);
				}
			}
		}
		
		private function onLetterMouseDown(e:MouseEvent):void
		{
			_isMouseDown = true;
			_firstLetterBox = e.target as LetterBox;
			_wordDragBuffer = new Vector.<LetterBox>();
			_wordDragBuffer.push(LetterBox(e.target));
			var highlight:Sprite = new Sprite();
			highlight.graphics.lineStyle(20, 0xff0000, 0.3);
			highlight.graphics.moveTo(e.target.x, e.target.y);
			addChildAt(highlight,0);
			_hightLight = highlight;
		}
		
		private function onLetterMouseUp(e:MouseEvent):void
		{
			_isMouseDown = false;
			_wordDragBuffer.sort(sortLetters);
			var selectedWord:String="";
			for each(var lb:LetterBox in _wordDragBuffer) selectedWord += lb.letter;
			
			if (_words.indexOf(selectedWord) == -1) {
				removeChild(_hightLight);
			}
			else {
				//Woo hoo!! We got one right
				var trans:ColorTransform= _hightLight.transform.colorTransform;
				trans.color = 0x00ff00;
				_hightLight.transform.colorTransform = trans;
				dispatchEvent(new WordFoundEvent(selectedWord));
				
				//tidy up
				for each(lb in _wordDragBuffer) lb.mouseEnabled = false;
			}
		}
		
		private function sortLetters(a:LetterBox, b:LetterBox):int
		{
			if (a.x > b.x || a.y > b.y) return 1;
			if (a.x < b.x || a.y < b.y) return -1;
			else return 0;
		}
		
		private function onLetterMouseOver(e:MouseEvent):void
		{
			if (_isMouseDown && (e.target.y==_firstLetterBox.y || e.target.x==_firstLetterBox.x) ) {
				if (_wordDragBuffer.indexOf(e.target) == -1) {
					_wordDragBuffer.push(LetterBox(e.target));
					_hightLight.graphics.lineTo(e.target.x, e.target.y);
				}
			}
		}
		
		private function resetGrid():void
		{
			//poopulate the grid with *'s...
			_lettersGrid = new Array();
			for (var r:int = 0; r < _gridHeight; r++) {
				var row:Array = new Array();
				for (var c:int = 0; c < _gridWidth; c++) {
					row.push("*");
				}
				_lettersGrid.push(row);
			}
		}
		
		private function fillGrid():void
		{
			for (var r:int = 0; r < _gridHeight; r++) {
				for (var c:int = 0; c < _gridWidth; c++) {
					if (_lettersGrid[r][c] == "*") _lettersGrid[r][c] = String.fromCharCode(65+int(Math.random()*25));
				}
			}
		}
		
		private function isValid(word:String,startingRow:int, startingCol:int, orienatation:String):Boolean
		{
			var i:int;
			if (orienatation == ORIENTATION_HORIZONTAL) {
				for (i = 0; i < _wordWidth; i++) {
					if (_lettersGrid[startingRow][startingCol + i] != "*") return false;
				}
				//if we've gotten here, it must be ok to add the word to the grid
				for (i = 0; i < _wordWidth; i++) {
					_lettersGrid[startingRow][startingCol + i] = word.charAt(i);
				}
			}
			else if (orienatation == ORIENTATION_VERTICAL) {
				for (i = 0; i < _wordWidth; i++) {
					if (_lettersGrid[startingRow+i][startingCol] != "*") return false;
				}
				//if we've gotten here, it must be ok to add the word to the grid
				for (i = 0; i < _wordWidth; i++) {
					_lettersGrid[startingRow + i][startingCol] = word.charAt(i);
				}
			}
			else {
				throw(new Error("invalid orientation!"));
			}
			
			return true;
		}
		
		private function cleanUp():void
		{
			while (numChildren) removeChildAt(0);
			resetGrid();
		}
	}

}